﻿namespace EFS.RC.CC.Presences.Operators.Distribution
{
	/// <summary>
	/// Distribution for an agent
	/// </summary>
	internal class Agent: EFS.Common.Async.AsyncRoot, System.IComparable
	{
		#region Composition

		// async access
		private object syncAccess = new object();

		/// Agent presence
		private EFS.RC.CC.Presences.Operators.OfficeService.Agent agentPresence = null;

		// Distribution
		private EFS.RC.CC.Presences.Operators.Distribution.List agentsDistribution = null;

		/// Skill Value
		private System.Int32 skillLevel = 0;
		
		#endregion

		#region Delegates

		/// <summary>
		/// Ready for distribution
		/// </summary>
		public delegate void DistributeReady(EFS.RC.CC.Presences.Operators.Distribution.Agent agentDistribution);

		/// <summary>
		/// Distribute Stopped
		/// </summary>
		public DistributeReady OnDistributeReady = null;

		/// <summary>
		/// Remove for distribution
		/// </summary>
		public delegate void DistributeStopped(EFS.RC.CC.Presences.Operators.Distribution.Agent agentDistribution);

		/// <summary>
		/// Distribute Stopped
		/// </summary>
		public DistributeStopped OnDistributeStopped = null;

		#endregion

		#region Constructor

		/// <summary>
		/// Constructor
		/// </summary>
		/// <param name="operatorsDistribution"></param>
		/// <param name="operatorsOfficeServiceEndPointApplication"></param>
		public Agent(EFS.RC.CC.Presences.Operators.Distribution.List agentsDistribution, EFS.RC.CC.Presences.Operators.OfficeService.Agent agentPresence)
		{
			// check
			EFS.Common.Verify.Reference(agentPresence, "agentPresence");

			// set
			this.agentsDistribution = agentsDistribution;
			this.agentPresence = agentPresence;

			// register for deployment load
			this.agentPresence.OnDeploymentLoad += OnDeploymentReloaded;
		}

		#endregion

		#region Usage

		/// <summary>
		/// Describe this
		/// </summary>
		/// <returns></returns>
		public override System.String Describe()
		{
			return System.String.Format("EFS.RC.CC.Presences.Operators.Distribution.Agent [{0}] [{1}]", agentPresence.Describe(), agentsDistribution.Describe());
		}

		/// <summary>
		/// Begin startup
		/// </summary>
		public EFS.Common.Async.AsyncProcess BeginDistribute()
		{
			// log
			EFS.EventLog.Log.LogInfo("BeginDistribute", this);

			// add to distribution
			return BeginAsyncProcess2(AddToDistribution);
		}

		/// <summary>
		/// Begin startup
		/// </summary>
		public EFS.Common.Async.AsyncProcess EndDistribute()
		{
			// log
			EFS.EventLog.Log.LogInfo("EndDistribute", this);

			// remove from distribution
			return BeginAsyncProcess2(RemoveFromDistribution);
		}

		/// <summary>
		/// Agent presence
		/// </summary>
		public EFS.RC.CC.Presences.Operators.OfficeService.Agent AgentPresence
		{
			get { return agentPresence; }
		}

		/// <summary>
		/// Agent distribution
		/// </summary>
		public EFS.RC.CC.Presences.Operators.Distribution.List AgentsDistribution
		{
			get { return agentsDistribution; }
		}

		/// Skill Value
		public System.Int32 SkillLevel 
		{ 
			get 
			{ 
				return skillLevel; 
			} 
		}

		/// <summary>
		/// Compare
		/// </summary>
		/// <param name="obj"></param>
		/// <returns></returns>
		public System.Int32 CompareTo(object obj)
		{
			// case
			Agent agentDistribution = obj as Agent;

			// check 
			if (agentDistribution != null)
			{
				// compare
				return 0 - skillLevel.CompareTo(agentDistribution.skillLevel);
			}

			// type issue
			throw new System.ArgumentException("Compare class different");
		}

		#endregion

		#region Runtime

		/// <summary>
		/// Unhandled exception
		/// </summary>
		/// <param name="ex"></param>
		protected override void OnException(System.Exception ex)
		{
			// check
			EFS.Common.Verify.Reference(ex, "ex");

			// log
			EFS.EventLog.Log.LogException(ex, this);

			// SAL
			EFS.RC.CC.Tools.Loggers.SAL.Add(null, "OnException", ex, this);
		}

		/// <summary>
		/// Deployment reload
		/// </summary>
		private void OnDeploymentReloaded(EFS.RC.CC.Presences.Operators.OfficeService.Agent agentOperator)
		{
			// log
			EFS.EventLog.Log.LogInfo("OnDeploymentReloaded", this);

			// check
			EFS.Common.Verify.Reference(agentPresence, "agentPresence");

			// check
			if (!this.agentPresence.Equals(agentPresence))
			{
				throw new System.InvalidOperationException("Deployment reload for different agent");
			}

			// get skill level
			skillLevel = this.agentPresence.GetSkillLevel(agentsDistribution.CustomersOfficeServiceEndPointApplication.ApplicationPresence.PresenceEndPointDeployment.SkillID.Value);

			// check skill
			if (0 == skillLevel)
			{
				// remove delegate
				agentPresence.OnDeploymentLoad -= OnDeploymentReloaded;

				// can not keep, no skill
				EndDistribute();
			}
		}

		/// <summary>
		/// Add
		/// </summary>
		private void AddToDistribution()
		{
			// get skill level
			skillLevel = agentPresence.GetSkillLevel(agentsDistribution.CustomersOfficeServiceEndPointApplication.ApplicationPresence.PresenceEndPointDeployment.SkillID.Value);

			// check skill
			if (0 == skillLevel)
			{
				// can not add, no skill
				EndDistribute();
			}

			// notify
			if (null != OnDistributeReady)
			{
				try
				{
					OnDistributeReady(this);
				}
				catch (System.Exception ex)
				{
					// log
					EFS.EventLog.Log.LogException(ex, this);
				}
			}
		}

		/// <summary>
		/// Remove
		/// </summary>
		public void RemoveFromDistribution()
		{
			// loack access
			if (null != OnDistributeStopped)
			{
				try
				{
					OnDistributeStopped(this);
				}
				catch (System.Exception ex)
				{
					// log
					EFS.EventLog.Log.LogException(ex, this);
				}
			}
		}

		#endregion
	}
}
